﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ApplLogic.ApplClasses;
using ApplLogic.DbToApplConvertor;
using Entities;
using DAL;

namespace ApplLogic.ApplDbMediators
{
    public class ApplDbRequestMediator
    {
        private DataService m_DataService = DataService.Instance;

        private static volatile ApplDbRequestMediator s_Instance = null;
        private static object s_InstanceLockObj = new Object();

        private ApplDbRequestMediator() { }

        public static ApplDbRequestMediator Instance
        {
            get
            {
                if (s_Instance == null)
                {
                    lock (s_InstanceLockObj)
                    {
                        if (s_Instance == null)
                        {
                            s_Instance = new ApplDbRequestMediator();
                        }
                    }
                }

                return s_Instance;
            }
        }

        //public void AddShiftToWorkerWithType(ApplSingleRequest request, bool saveChanges = false)
        //{
        //    m_DataService.AddRequestShiftToWorker(request.ApplShift.Id, request.ApplWorker.PersonalDetails.Id, ApplSingleRequest.ConvertEnumTypeToString(request.Type), saveChanges);
        //}

        public List<ApplWorker> GetAllWorkersThatAskedForShiftsInRange(DateTime startTime, DateTime endTime)
        {
            List<ApplWorker> applWorkers = new List<ApplWorker>();
            foreach (Worker worker in m_DataService.GetAllWorkersThatAskedForShiftsInRange(startTime, endTime))
            {
                applWorkers.Add(DbApplObjectConvertor.CreateApplWorkerFromDbWorker(worker));
            }

            return applWorkers;
        }

        public List<ApplWorker> GetAllWorkersThatNotAskedForanyShiftInRange(DateTime startTime, DateTime endTime)
        {
            List<ApplWorker> applWorkers = new List<ApplWorker>();
            foreach (Worker worker in m_DataService.GetAllWorkersThatNotAskedForanyShiftInRange(startTime, endTime))
            {
                applWorkers.Add(DbApplObjectConvertor.CreateApplWorkerFromDbWorker(worker));
            }

            return applWorkers;
        }

        public void RenterAllRequestsOfWorker(string workerId, DateTime startTime, DateTime endTime, List<ApplSingleRequest> newRequests, bool saveChanges = false)
        {
            List<Request> dbRequests = new List<Request>();
            foreach (ApplSingleRequest request in newRequests)
            {
                dbRequests.Add(DbApplObjectConvertor.CreateDbRequestFromApplRequest(request));
            }
            m_DataService.RenterAllRequestsOfWorker(workerId, startTime, endTime, dbRequests, true);
        }

        public void DeleteRequest(ApplSingleRequest requestToDelete, bool saveChanges = false)
        {
            m_DataService.DeleteRequest(requestToDelete.ApplWorker.PersonalDetails.Id, requestToDelete.ApplShift.Id, saveChanges);
        }

        public void UpdateRequestType(ApplSingleRequest updatedRequest, bool saveChanges = false)
        {
            m_DataService.UpdateRequestType(updatedRequest.ApplWorker.PersonalDetails.Id, updatedRequest.ApplShift.Id, 
                ApplSingleRequest.ConvertEnumTypeToString(updatedRequest.Type), saveChanges);
        }

        public List<ApplWorker> GetAllWorkersThatAskedForShift(string shiftId, DateTime startTime, DateTime endTime)
        {
            List<ApplWorker> applWorkers = new List<ApplWorker>();
            foreach (Worker worker in m_DataService.GetAllWorkersThatAskedForShift(shiftId, startTime, endTime))
            {
                applWorkers.Add(DbApplObjectConvertor.CreateApplWorkerFromDbWorker(worker));
            }

            return applWorkers;
        }

        public List<ApplWorker> GetAllWorkersThatAskedForShiftWithType(string shiftId, eType type, DateTime startTime, DateTime endTime)
        {
            List<ApplWorker> applWorkers = new List<ApplWorker>();
            foreach (Worker worker in m_DataService.GetAllWorkersThatAskedForShift(shiftId, 
                ApplSingleRequest.ConvertEnumTypeToString(type), startTime, endTime))
            {
                applWorkers.Add(DbApplObjectConvertor.CreateApplWorkerFromDbWorker(worker));
            }

            return applWorkers;
        }

        public List<string> GetAllWorkersIdsThatAskedForShiftWithType(string shiftId, eType type, DateTime startTime, DateTime endTime)
        {
            List<string> applWorkersIds = new List<string>();
            foreach (Worker worker in m_DataService.GetAllWorkersThatAskedForShift(shiftId, 
                ApplSingleRequest.ConvertEnumTypeToString(type), startTime, endTime))
            {
                ApplWorker applWorker = DbApplObjectConvertor.CreateApplWorkerFromDbWorker(worker);
                applWorkersIds.Add(applWorker.PersonalDetails.Id);
            }

            return applWorkersIds;
        }

        public List<ApplShift> GetAllShiftsThatWorkerAsked(string workerId, DateTime startTime, DateTime endTime)
        {
            List<ApplShift> applShifts = new List<ApplShift>();
            foreach (Shift shift in m_DataService.GetAllShiftsThatWorkerAsked(workerId, startTime, endTime))
            {
                applShifts.Add(DbApplObjectConvertor.CreateApplShiftFromDbShift(shift));
            }

            return applShifts;
        }

        public List<ApplShift> GetAllShiftsThatWorkerAskedWithType(string workerId, eType type,  DateTime startTime, DateTime endTime)
        {
            List<ApplShift> applShifts = new List<ApplShift>();
            foreach (Shift shift in m_DataService.GetAllShiftsThatWorkerAsked(workerId, 
                ApplSingleRequest.ConvertEnumTypeToString(type), startTime, endTime))
            {
                applShifts.Add(DbApplObjectConvertor.CreateApplShiftFromDbShift(shift));
            }

            return applShifts;
        }

        public List<string> GetAllShiftsIdsThatWorkerAskedWithType(string workerId, eType type, DateTime startTime, DateTime endTime)
        {
            List<string> applShiftsIds = new List<string>();
            foreach (string shiftId in m_DataService.GetAllShiftsIdsThatWorkerAsked(workerId,
                ApplSingleRequest.ConvertEnumTypeToString(type), startTime, endTime))
            {
                applShiftsIds.Add(shiftId);
            }

            return applShiftsIds;
        }

        public Dictionary<ApplWorker, List<ApplSingleRequest>> GetAllRequestsOfAllWorkers(DateTime startTime, DateTime endTime)
        {
            Dictionary<ApplWorker, List<ApplSingleRequest>> allRequestsByWorkers = new Dictionary<ApplWorker, List<ApplSingleRequest>>();
            foreach (Worker dbWorker in m_DataService.GetAllWorkers())
            {
                ApplWorker applWorker = DbApplObjectConvertor.CreateApplWorkerFromDbWorker(dbWorker);
                List<ApplSingleRequest> shiftsOfWorker = new List<ApplSingleRequest>();
                foreach (Shift dbShift in m_DataService.GetAllShiftsThatWorkerAsked(applWorker.PersonalDetails.Id, startTime, endTime))
                {
                    shiftsOfWorker.Add(new ApplSingleRequest()
                    {
                        ApplShift = DbApplObjectConvertor.CreateApplShiftFromDbShift(dbShift),
                        ApplWorker = applWorker,
                        Type = ApplSingleRequest.ConvertStringToEnum(
                            m_DataService.GetRequestByID(dbWorker.WorkerID, dbShift.ShiftID).Type)
                    });
                }
                allRequestsByWorkers.Add(applWorker, shiftsOfWorker);
            }
            return allRequestsByWorkers;
        }

        public Dictionary<ApplWorker, List<ApplShift>> GetAllRequestsOfAllWorkersWithType(eType type, DateTime startTime, DateTime endTime)
        {
            Dictionary<ApplWorker, List<ApplShift>> allRequestsByWorkers = new Dictionary<ApplWorker, List<ApplShift>>();
            foreach (Worker dbWorker in m_DataService.GetAllWorkers())
            {
                ApplWorker applWorker = DbApplObjectConvertor.CreateApplWorkerFromDbWorker(dbWorker);
                List<ApplShift> shiftsOfWorker = new List<ApplShift>();
                foreach (Shift dbShift in m_DataService.GetAllShiftsThatWorkerAsked(applWorker.PersonalDetails.Id, 
                    ApplSingleRequest.ConvertEnumTypeToString(type), startTime, endTime))
                {
                    shiftsOfWorker.Add(DbApplObjectConvertor.CreateApplShiftFromDbShift(dbShift));
                }
                allRequestsByWorkers.Add(applWorker, shiftsOfWorker);
            }
            return allRequestsByWorkers;
        }

        public Dictionary<ApplShift, List<ApplSingleRequest>> GetAllRequestsOfAllShifts(DateTime startTime, DateTime endTime)
        {
            Dictionary<ApplShift, List<ApplSingleRequest>> allRequestsByShifts = new Dictionary<ApplShift, List<ApplSingleRequest>>();
            foreach (Shift dbShift in m_DataService.GetAllShifts())
            {
                ApplShift applShift = DbApplObjectConvertor.CreateApplShiftFromDbShift(dbShift);
                List<ApplSingleRequest> workersOfShift = new List<ApplSingleRequest>();
                foreach (Worker dbWorker in m_DataService.GetAllWorkersThatAskedForShift(applShift.Id, startTime, endTime))
                {
                    workersOfShift.Add(new ApplSingleRequest()
                    {
                        ApplShift = applShift,
                        ApplWorker = DbApplObjectConvertor.CreateApplWorkerFromDbWorker(dbWorker),
                        Type = ApplSingleRequest.ConvertStringToEnum(
                            m_DataService.GetRequestByID(dbWorker.WorkerID, dbShift.ShiftID).Type)
                    });
                }
                if (workersOfShift.Count > 0)
                {
                    allRequestsByShifts.Add(applShift, workersOfShift);
                }
            }
            return allRequestsByShifts;
        }

        public Dictionary<ApplShift, List<ApplSingleRequest>> GetAllRequestsOfAllShiftsOfWorker(DateTime startTime, DateTime endTime, string workerId)
        {
            Dictionary<ApplShift, List<ApplSingleRequest>> allRequestsByShifts = new Dictionary<ApplShift, List<ApplSingleRequest>>();
            foreach (Shift dbShift in m_DataService.GetAllShifts())
            {
                ApplShift applShift = DbApplObjectConvertor.CreateApplShiftFromDbShift(dbShift);
                List<ApplSingleRequest> workersOfShift = new List<ApplSingleRequest>();
                foreach (Worker dbWorker in m_DataService.GetAllWorkersThatAskedForShift(applShift.Id, startTime, endTime))
                {
                    if (dbWorker.WorkerID == workerId)
                    {
                        workersOfShift.Add(new ApplSingleRequest()
                                               {
                                                   ApplShift = applShift,
                                                   ApplWorker =
                                                       DbApplObjectConvertor.CreateApplWorkerFromDbWorker(dbWorker),
                                                   Type = ApplSingleRequest.ConvertStringToEnum(
                                                       m_DataService.GetRequestByID(dbWorker.WorkerID, dbShift.ShiftID).
                                                           Type)
                                               });
                    }
                }
                if (workersOfShift.Count > 0)
                {
                    allRequestsByShifts.Add(applShift, workersOfShift);
                }
            }
            return allRequestsByShifts;
        }

        public Dictionary<ApplShift, List<ApplWorker>> GetAllRequestsOfAllShiftsWithType(eType type, DateTime startTime, DateTime endTime)
        {
            Dictionary<ApplShift, List<ApplWorker>> allRequestsByShifts = new Dictionary<ApplShift, List<ApplWorker>>();
            foreach (Shift dbShift in m_DataService.GetAllShifts())
            {
                ApplShift applShift = DbApplObjectConvertor.CreateApplShiftFromDbShift(dbShift);
                List<ApplWorker> workersOfShift = new List<ApplWorker>();
                foreach (Worker dbWorker in m_DataService.GetAllWorkersThatAskedForShift(applShift.Id, 
                   ApplSingleRequest.ConvertEnumTypeToString(type), startTime, endTime))
                {
                    workersOfShift.Add(DbApplObjectConvertor.CreateApplWorkerFromDbWorker(dbWorker));
                }
                if (workersOfShift.Count > 0)
                {
                    allRequestsByShifts.Add(applShift, workersOfShift);
                }
            }
            return allRequestsByShifts;
        }

        public void CopyRequestFrom(string workerId, DateTime startTime, DateTime endTime)
        {
            ApplWorker workerToAdd = ApplDbWorkerMediator.Instance.GetWorker(workerId);
            List<ApplShift> sourceShiftsWanted = GetAllShiftsThatWorkerAskedWithType(workerId, eType.WANTED, startTime, endTime);
            List<ApplShift> sourceShiftsForb = GetAllShiftsThatWorkerAskedWithType(workerId, eType.FORBIDDEN, startTime, endTime);
            List<ApplSingleRequest> newRequest = new List<ApplSingleRequest>();
            foreach (var sourceShift in sourceShiftsWanted)
            {
                ApplShift shiftToAdd = DbApplObjectConvertor.CreateApplShiftFromDbShift(m_DataService.GetShiftByDateRange(sourceShift.BeginTime.AddDays(7), sourceShift.EndTime.AddDays(7)));
                ApplSingleRequest request = new ApplSingleRequest
                                  {
                                      ApplShift = shiftToAdd,
                                      ApplWorker = workerToAdd,
                                      Type = eType.WANTED
                                  };
                newRequest.Add(request);

            }

            foreach (var sourceShift in sourceShiftsForb)
            {
                ApplShift shiftToAdd = DbApplObjectConvertor.CreateApplShiftFromDbShift(m_DataService.GetShiftByDateRange(sourceShift.BeginTime.AddDays(7), sourceShift.EndTime.AddDays(7)));
                ApplSingleRequest request = new ApplSingleRequest
                {
                    ApplShift = shiftToAdd,
                    ApplWorker = workerToAdd,
                    Type = eType.FORBIDDEN
                };
                newRequest.Add(request);
            }
            RenterAllRequestsOfWorker(workerId, startTime.AddDays(7), endTime.AddDays(7), newRequest, true);

        }
    }
}
